﻿#region License
/*
 * Copyright ©2011-2012 EasyMon Project
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *  
 */
#endregion

using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using EasyMon.Common.Sources;
using EasyMon.Common.Values;
using EasyMon.Win.Agent.Utils;

namespace EasyMon.Win.Agent.Extensions
{
    public static class ProcessSourceExtensions
    {
        public static ProcessValue Query(this ProcessSource source)
        {
            var process = DiscoverProcess(source.PrimaryProcessName, source.PrimaryProcessMainModulePath);

            if (process == null)
            {
                process = DiscoverProcess(source.AlternativeProcessName, source.AlternativeProcessMainModulePath);

                if (process == null)
                {
                    return new ProcessValue
                    {
                        DisplayName = source.DisplayName,
                        Status = ValueStatus.Unavailable
                    };
                }
            }

            var perfCounterInstance = process.GetPerfCounterInstanceName();

            var list = new ConcurrentBag<PerfCounterValue>();

            Parallel.ForEach(source.PerfCounters, x => list.Add(x.Query(perfCounterInstance)));

            var value = new ProcessValue
            {
                DisplayName = source.DisplayName,
                Status = ValueStatus.Good,
                PerfCounters = list.OrderBy(x => x.DisplayName).ToArray()
            };

            value.SynchStatusWithChildren(value.PerfCounters);

            return value;
        }

        private static Process DiscoverProcess(string processName, string mainModulePath)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(processName))
                    return null;

                var processes = Process.GetProcessesByName(processName);

                if (String.IsNullOrWhiteSpace(mainModulePath) && processes.Length == 1)
                    return processes[0];

                return processes.FirstOrDefault(process => String.Compare(process.MainModule.FileName, mainModulePath, StringComparison.OrdinalIgnoreCase) == 0);
            }
            catch (Exception e)
            {
                Trace.WriteLine(e.ToString());
                return null;
            }
        }

        public static string GetPerfCounterInstanceName(this Process process)
        {
            try
            {
                foreach (var instanceName in new PerformanceCounterCategory("Process", process.MachineName).GetInstanceNames())
                {
                    var counter = new ReadOnlyPerformanceCounter("Process", "ID Process", instanceName);
                    if (counter.RawValue == process.Id)
                        return instanceName;
                }

                Trace.WriteLine("Process " + process.Id + " is not found");
            }
            catch (Exception e)
            {
                Trace.WriteLine(e.ToString());
            }

            return null;
        }
    }
}
